﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Data;

namespace common.controls
{
    public class GridEventArgs
    {
        public GridEventArgs(){}
        public GridEventArgs(int rowIndex , int columnIndex)
        { 
            RowIndex = rowIndex;
            ColumnIndex = columnIndex;
        }
        public int RowIndex = -1, ColumnIndex = -1;
    }
    public class GridRowValidateEventArgs
    {
        public bool HaveError = false;
        public myString ErrorText = new myString();
    }
    public class baseDataGridView : DataGridView
    {
        public baseDataGridView()
        {
            this.RowTemplate.Height = 25;
            this.AutoGenerateColumns = false;
            this.AutoArrange();

            this.CreateContextMenu();
            this.ContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.DoWhenContextMenuStripOpening);
            this.myOnImport += new OnDataExchangeNeed(DefaultImport);
            this.myOnExport += new OnDataExchangeNeed(DefaultExport);
        }

        private bool _IsOnProcessing = false;
        public bool IsOnProcessing
        {
            get { return _IsOnProcessing; }
            set 
            { 
                _IsOnProcessing = value; 
            }
        }

        protected BindingSource myDataSource = null;
        public virtual void Init(BindingSource  dataSource)
        {
            this.myDataSource = dataSource;
            this.DataSource = dataSource;
        }
        //Columns that size is fixed / not adjusted dynamically
        public StringCollection myFixedSizedColumns = new StringCollection();
        public StringCollection myDisableColumns = new StringCollection();

        //Quick find
        string qfKeyPressBuff = "";
        DateTime qfKeyPressBuffTime = DateTime.Now;
        private short qfKeyCaptureInMiliSec = 500;
        public bool myUseQuickFind = false;
        public short myQuickFindColumnId = 0;
        private void QuickFind()
        {
            if (this.myQuickFindColumnId < 0 || this.myQuickFindColumnId >= this.ColumnCount) return;
            for (int idx = 0; idx < this.RowCount; idx++)
            {
                if (this.Rows[idx].Cells[this.myQuickFindColumnId].Value.ToString().ToUpper().StartsWith(qfKeyPressBuff))
                {
                    this.CurrentCell = this.Rows[idx].Cells[this.myQuickFindColumnId];
                    return;
                }
            }
        }

        public enum ColumnTypes : byte { All, Visible, VisibleAndEnable };
        protected StringCollection GetColumnNames(ColumnTypes mode)
        {
            //Keep the column order
            myTypes.SortedList list = new myTypes.SortedList();
            switch (mode)
            {
                case ColumnTypes.Visible:
                    for (int idx = 0; idx < this.ColumnCount; idx++)
                    {
                        if (this.Columns[idx].Visible == false) continue;
                        if (StringLibs.IsNullOrEmpty(this.Columns[idx].DataPropertyName)) continue;

                        if (list.ContainsValue(this.Columns[idx].DataPropertyName)) continue;
                        list.Add(this.Columns[idx].DisplayIndex, this.Columns[idx].DataPropertyName);
                    }
                    break;
                case ColumnTypes.VisibleAndEnable:
                    for (int idx = 0; idx < this.ColumnCount; idx++)
                    {
                        if (this.Columns[idx].Visible == false) continue;
                        if (this.myDisableColumns.Contains(this.Columns[idx].Name)) continue;
                        if (StringLibs.IsNullOrEmpty(this.Columns[idx].DataPropertyName)) continue;

                        if (list.ContainsValue(this.Columns[idx].DataPropertyName)) continue;
                        list.Add(this.Columns[idx].DisplayIndex, this.Columns[idx].DataPropertyName);
                    }
                    break;
                default:
                    for (int idx = 0; idx < this.ColumnCount; idx++)
                    {
                        if (StringLibs.IsNullOrEmpty(this.Columns[idx].DataPropertyName)) continue;
                        if (list.ContainsValue(this.Columns[idx].DataPropertyName)) continue;
                        list.Add(this.Columns[idx].DisplayIndex, this.Columns[idx].DataPropertyName);
                    }
                    break;
            }
            StringCollection columnList = new StringCollection();
            foreach (object obj in list)
            {
                columnList.Add((((System.Collections.DictionaryEntry)obj).Value).ToString());
            }
            return columnList;
        }
        public StringCollection myExportColumns = new StringCollection();
        public void SetExportColumn(ColumnTypes type)
        {
            this.myExportColumns.Clear();
            this.myExportColumns.AddRange(common.StringLibs.Collection2List(GetColumnNames(type)));
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (this.myUseQuickFind)
            {
                TimeSpan ts = DateTime.Now.Subtract(this.qfKeyPressBuffTime);
                if (ts.Milliseconds < this.qfKeyCaptureInMiliSec)
                {
                    this.qfKeyPressBuff += e.KeyChar.ToString().ToUpper();
                }
                else
                {
                    this.qfKeyPressBuff = e.KeyChar.ToString().ToUpper();
                    this.qfKeyPressBuffTime = DateTime.Now;
                }
                QuickFind();
            }
        }
        protected override void OnDataError(bool displayErrorDialogIfNoHandler, System.Windows.Forms.DataGridViewDataErrorEventArgs e)
        {
            e.Cancel = true;
            e.ThrowException = false;
        }
        
        public delegate void OnValuesNeeded(DataGridViewRowEventArgs e);
        public event OnValuesNeeded myOnValuesNeeded = null;
        public override string ToString() { return typeof(DataGridView).Name; }

        public string myAutoFitColumn = null;
        public void AutoFitGridColumn(string colName)
        {
            if (colName == null || this.Columns[colName] == null) return;

            if (colName.Trim() == "")
            {
                AutoFitGridColumn();
                return;
            }
            int w = SysLibs.VisibleGridColumnWidth(this);
            w -= this.Columns[colName].Width - (this.RowHeadersVisible ? this.RowHeadersWidth : 2) - SystemInformation.VerticalScrollBarThumbHeight - 2;
            if (this.Width > w)  
                this.Columns[colName].Width = this.Width - w;
        }
        public void AutoFitGridColumn()
        {
            myTypes.Distribution widthDist = new myTypes.Distribution();
            int totalWidth = 0, totalFixWidth = 0;

            for (int idx = 0; idx < this.Columns.Count; idx++)
            {
                if (!this.Columns[idx].Visible) continue;
                if (this.Columns[idx].Name.Trim() == "") continue;
                if (this.myFixedSizedColumns.Contains(this.Columns[idx].Name))
                {
                    totalFixWidth += this.Columns[idx].Width;
                    continue;
                }
                totalWidth += this.Columns[idx].Width;
                widthDist.Add(this.Columns[idx].Name, this.Columns[idx].Width);
            }
            totalWidth = this.Width - totalFixWidth - (this.RowHeadersVisible ? this.RowHeadersWidth : 2) - SystemInformation.VerticalScrollBarThumbHeight - 2 - totalWidth;
            if (!widthDist.Distribute(totalWidth, 0)) return;
            System.Collections.SortedList disResult = widthDist.GetDistribution();
            int value = 0;
            string tmp;
            for (int idx = 0; idx < disResult.Count; idx++)
            {
                tmp = disResult.GetKey(idx).ToString();
                int.TryParse(disResult[tmp].ToString(), out value);
                this.Columns[tmp].Width += value;
            }
        }

        public virtual bool CheckData()
        {
            return true;
        }
        public delegate void myRowValidate(DataGridViewRow row, GridRowValidateEventArgs e);
        public bool DoValidateData(myRowValidate validateFunc)
        {
            if (validateFunc == null) return true;

            bool retVal = true;
            for (int idx = 0; idx < this.RowCount; idx++)
            {
                this.Rows[idx].ErrorText = "";

                if (this.Rows[idx].DataBoundItem == null) continue;

                GridRowValidateEventArgs e = new GridRowValidateEventArgs();
                validateFunc(this.Rows[idx], e);
                if (e.HaveError)
                {
                    this.Rows[idx].DefaultCellStyle.BackColor = Settings.sysColorHiLightBG1;
                    this.Rows[idx].DefaultCellStyle.ForeColor = Settings.sysColorHiLightFG1;
                    this.Rows[idx].ErrorText = e.ErrorText.ToString();
                    retVal = false;
                }
            }
            return retVal;
        }

        //Context menu
        private myTypes.DictionaryList myContextMenuList = new myTypes.DictionaryList();
        protected void ClearContextMenu()
        {
            if (this.ContextMenuStrip == null) this.ContextMenuStrip = new ContextMenuStrip();
            this.ContextMenuStrip.Items.Clear();
            myContextMenuList.Clear();
        }
        private void DoWhenContextMenuStripOpening(object sender, CancelEventArgs e)
        {
            try
            {
                WhenContextMenuStripOpening(sender, e);
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }

        protected virtual void CreateContextMenu()
        {
            ClearContextMenu();
            AddContextMenu(myMenuName.Add, language.GetString("addLine"), addLine_Click);
            AddContextMenu(myMenuName.Delete, language.GetString("deleteLine"), deleteLine_Click);
            AddContextMenu(myMenuName.Copy, language.GetString("copyLine"), copyLines_Click);
            AddContextMenu(myMenuName.Import, language.GetString("importExcel"), importToGrid_Click);
            AddContextMenu(myMenuName.Export, language.GetString("exportExcel"), exportGrid_Click);
        }

        protected virtual void WhenContextMenuStripOpening(object sender, CancelEventArgs e)
        {
            ContextMenuEnable(myMenuName.Add, !this.isLockEdit);
            ContextMenuEnable(myMenuName.Delete, !this.isLockEdit);
            ContextMenuEnable(myMenuName.Copy, !this.isLockEdit);
            ContextMenuEnable(myMenuName.PasteToGrid, !this.isLockEdit);
            ContextMenuEnable(myMenuName.Import, !this.isLockEdit);
            ContextMenuEnable(myMenuName.Export, true);
            ContextMenuEnable(myMenuName.Copy, (this.SelectedRows.Count > 0));
        }

        public enum myMenuName : byte
        {
            Add, Delete, Copy, PasteToGrid, Export, Import, AdvancedExport,
            rItem1, rItem2, rItem3, rItem4, rItem5
        }; 
        public virtual void AddContextMenu(myMenuName name, string caption, EventHandler onClick)
        {
            if (myContextMenuList.Find(name.ToString()) != null) return;
            ToolStripItem menuItem = this.ContextMenuStrip.Items.Add(caption);
            menuItem.Name = name.ToString();
            if (onClick != null) menuItem.Click += new System.EventHandler(onClick);
            myContextMenuList.Add(menuItem.Name, menuItem);
        }
        public virtual void RemoveContextMenu(string key)
        {
            ToolStripItem foundMenu = (ToolStripItem)(myContextMenuList.Find(key));
            if (foundMenu == null) return;
            this.ContextMenuStrip.Items.Remove(foundMenu);
            myContextMenuList.Remove(key);
        }
        public virtual void ContextMenuEnable(myMenuName name, bool enable)
        {
            ToolStripItem foundMenu = (ToolStripItem)(myContextMenuList.Find(name.ToString()));
            if (foundMenu == null) return;
            foundMenu.Enabled = enable;
        }
        public virtual void ContextMenuVisable(myMenuName name, bool visable)
        {
            ToolStripItem foundMenu = (ToolStripItem)(myContextMenuList.Find(name.ToString()));
            if (foundMenu == null) return;
            foundMenu.Visible = visable;
        }

        public virtual bool AddLine()
        {
            DataGridViewRow curRow = (this.CurrentRow == null ? null : this.Rows[this.CurrentRow.Index]);
            DataRowView dr = (DataRowView)this.myDataSource.AddNew();

            DataGridViewRowEventArgs e = new DataGridViewRowEventArgs(this.CurrentRow);
            // To simulate the same behavior of _DefaultValuesNeeded event,
            // try to go to the cell where the Add was occured
            //if (curCell1 != null) myDetailGrid.CurrentCell = curCell1;
            DoAddNewLine(curRow, e);
            //??if (this.myOnNewLineAdded != null) this.myOnNewLineAdded(this);
            DoNeedRefresh();
            return true;
        }

        /// <summary>
        /// Copy from selected rows
        /// </summary>
        public virtual void CopyLines()
        {
            if (this.SelectedRows.Count <= 0)
            {
                SysLibs.ShowErrorMessage(language.GetString("selectDataToCopy"));
                return;
            }
            int[] selectedIdx = new int[this.SelectedRows.Count];
            for (int idx = 0; idx < this.SelectedRows.Count; idx++)
                selectedIdx[this.SelectedRows.Count - idx - 1] = this.SelectedRows[idx].Index;

            for (int idx = 0; idx < selectedIdx.Length; idx++)
            {
                DataRowView newRow = (System.Data.DataRowView)myDataSource.AddNew();
                if (newRow == null) continue;
                newRow.Row.ItemArray = ((DataRowView)this.Rows[selectedIdx[idx]].DataBoundItem).Row.ItemArray;
            }
            myDataSource.EndEdit();
            DoNeedRefresh();
        }

        /// <summary>
        /// Remove selected lines or current line
        /// </summary>
        /// <returns></returns>
        public virtual bool RemoveLine()
        {
            //Return seleted  rows
            if (this.SelectedRows.Count > 0)
            {
                while (this.SelectedRows.Count > 0)
                {
                    this.Rows.RemoveAt(this.SelectedRows[0].Index);
                }
            }
            else
            {
                //Return current row
                if (this.CurrentRow == null || this.CurrentRow.IsNewRow) return true;
                this.Rows.RemoveAt(this.CurrentRow.Index);
            }
            DoNeedRefresh();
            return true;
        }

        public virtual string GetImportFile()
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            common.DialogLibs.SetFileDialogEXCEL(openFileDialog);
            if (openFileDialog.ShowDialog() != DialogResult.OK) return null;
            string fileName = openFileDialog.FileName;
            if (!common.fileFuncs.FileExist(fileName))
            {
                common.SysLibs.ShowMessage("Tệp " + fileName + " không tồn tại!");
                return null;
            }
            return fileName;
        }

        public virtual string GetExportFile()
        {
            SaveFileDialog saveDialog = new SaveFileDialog();
            common.DialogLibs.SetFileDialogEXCEL(saveDialog);
            if (saveDialog.ShowDialog() != DialogResult.OK) return null;
            string fileName = saveDialog.FileName;
            return fileName;
        }

        protected bool GetExcelFileImport(out string fileName, out string sheetName)
        {
            sheetName = "Sheet1";
            fileName = GetImportFile();
            if (fileName == null) return false;
            if (common.fileFuncs.FileExist(fileName))
            {
                StringCollection sheetList = common.import.GetExcelSheetName(fileName);
                if (sheetList != null && sheetList.Count > 0) sheetName = sheetList[0];
            }
            return true;
        }
        protected bool GetExcelFileExport(out string fileName, out string sheetName)
        {
            sheetName = "Sheet1";
            fileName = GetExportFile();
            if (fileName == null) return false;
            if (common.fileFuncs.FileExist(fileName))
            {
                StringCollection sheetList = common.import.GetExcelSheetName(fileName);
                if (sheetList != null && sheetList.Count > 0) sheetName = sheetList[0];
            }
            return true;
        }
        public virtual void Import(string fromFile) { }
        public virtual void AutoArrange()
        {
            this.AutoFitGridColumn(this.myAutoFitColumn);
        }
        /// <summary>
        /// Import data from excel file
        /// </summary>
        protected virtual void DefaultImport()
        {
            string fileName, sheetName;
            if (GetExcelFileImport(out fileName, out sheetName) == false) return;

            DataTable tbl = new DataTable();
            if (!common.import.ImportFromExcel(fileName, sheetName,tbl)) return;

            SortedList<int, string> entryColumns = new SortedList<int, string>();
            for (int idx = 0; idx < this.ColumnCount; idx++)
            {
                if (this.Columns[idx].Visible == false) continue;
                if (this.myDisableColumns.Contains(this.Columns[idx].Name)) continue;
                if (StringLibs.IsNullOrEmpty(this.Columns[idx].DataPropertyName)) continue;
                entryColumns.Add(this.Columns[idx].DisplayIndex, this.Columns[idx].Name);
            }
            if (entryColumns.Count > tbl.Columns.Count)
            {
                common.SysLibs.ShowMessage("Tệp " + fileName + " không đúng định dạng !");
                return;
            }

            DataGridViewRow curRow = (this.CurrentRow == null ? null : this.Rows[this.CurrentRow.Index]);
            for (int idx1 = 0; idx1 < tbl.Rows.Count; idx1++)
            {
                this.myDataSource.AddNew();
                DataGridViewRowEventArgs addRow = new DataGridViewRowEventArgs(this.CurrentRow);
                // To simulate the same behavior of _DefaultValuesNeeded event,
                // try to go to the cell where the Add was occured
                //if (curCell1 != null) myDetailGrid.CurrentCell = curCell1;
                this.DoAddNewLine(curRow, addRow);

                int count = 0;
                foreach (var pair in entryColumns)
                {
                    addRow.Row.Cells[pair.Value].Value = tbl.Rows[idx1][count].ToString();
                    count++;
                }
            }
            myDataSource.EndEdit();
        }

        /// <summary>
        /// Import data from excel file
        /// </summary>
        /// 
        protected virtual DataTable GetExportData()
        {
            object dataObj = null;
            if (this.DataSource != null) dataObj = this.DataSource;
            else
            {
                if (this.myDataSource != null) dataObj = this.myDataSource;
                else return null;
            }

            if (dataObj.GetType() == typeof(DataView)) return ((DataView)dataObj).ToTable();
            if (dataObj.GetType() == typeof(BindingSource))
            {
                BindingSource dataSrc = (BindingSource)dataObj;
                if (dataSrc.DataSource.GetType() == typeof(DataView))
                {
                    return (dataSrc.DataSource as DataView).ToTable();
                }
                if (dataSrc.DataSource.GetType().BaseType == typeof(DataSet))
                {
                    DataSet ds = (DataSet)dataSrc.DataSource;
                    return (DataTable)(ds.Tables[dataSrc.DataMember]);
                }
                return ((DataTable)dataSrc.DataSource);
            }
            return ((DataTable)dataObj);
        }
        public virtual void DefaultExport()
        {
            string fileName, sheetName;
            if (GetExcelFileExport(out fileName, out sheetName) == false) return;

            DataTable tbl = GetExportData();
            if (tbl == null)
            {
                SysLibs.ShowMessage("Cannot get data to export !");
                return;
            }
            StringCollection exportColumns = GetColumnNames(ColumnTypes.VisibleAndEnable);
            if (common.Export.ExportToExcel(tbl, fileName,sheetName, exportColumns,null ))
                SysLibs.ShowMessage(String.Format(language.GetString("dataSavedTo"), fileName));
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            AutoArrange();
        }

        // some strange error when on new row ??? 
        protected override void OnCellDoubleClick(DataGridViewCellEventArgs e)
        {
            if (this.CurrentCell == null || myOnFind == null) return;
            if (e.RowIndex < 0 || e.RowIndex >= this.RowCount || e.ColumnIndex < 0 || e.ColumnIndex >= this.ColumnCount) return;
            try
            {
                base.OnCellDoubleClick(e);
                IsOnProcessing = true;
                if (this.CurrentCell.ValueType ==  typeof(System.String))
                    DoFind(this.CurrentCell.RowIndex, this.CurrentCell.ColumnIndex);
                IsOnProcessing = false;
            }
            catch (Exception er)
            {
                IsOnProcessing = false;
                ErrorHandler(this,er);
            }
        }
        protected override void OnCellValidated(DataGridViewCellEventArgs e)
        {
            if (this.CurrentCell == null) return;
            if (e.RowIndex <0 || e.RowIndex >= this.RowCount ||   e.ColumnIndex <0 || e.ColumnIndex >= this.ColumnCount) return;

            if (IsOnProcessing) return;
            try
            {
                IsOnProcessing = true;
                if (myOnCellValidated != null)
                    myOnCellValidated(this,new GridEventArgs(e.RowIndex, e.ColumnIndex));
                base.OnCellValidated(e);
                IsOnProcessing = false;
            }
            catch (Exception er)
            {
                IsOnProcessing = false;
                ErrorHandler(this, er);
            }
        }
        protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
        {
            if (IsOnProcessing) return;
            if (this.CurrentCell == null) return;
            if (e.RowIndex < 0 || e.RowIndex >= this.RowCount || e.ColumnIndex < 0 || e.ColumnIndex >= this.ColumnCount) return;
            try
            {
                IsOnProcessing = true;
                base.OnCellValueChanged(e);
                if (myOnCellValueChanged != null) myOnCellValueChanged(this,new GridEventArgs(e.RowIndex, e.ColumnIndex));
                if (this.CurrentCell.ValueType == typeof(System.String) && SysLibs.HaveFindMarker(this.CurrentCell.EditedFormattedValue.ToString()))
                {
                    DoFind(e.RowIndex, e.ColumnIndex);
                }
                if (myOnNeedRefresh != null)
                {
                    GridEventArgs arg = new GridEventArgs();
                    arg.RowIndex = e.RowIndex; arg.ColumnIndex = e.ColumnIndex;
                    myOnNeedRefresh(this, arg);
                }
                IsOnProcessing = false;
            }
            catch (Exception er)
            {
                IsOnProcessing = false;
                ErrorHandler(this, er);
            }
        }
        protected override void OnCellEnter(DataGridViewCellEventArgs e)
        {
            if (this.CurrentCell == null) return;
            if (e.RowIndex < 0 || e.RowIndex >= this.RowCount || e.ColumnIndex < 0 || e.ColumnIndex >= this.ColumnCount) return;
            if (IsOnProcessing) return;
            try
            {
                IsOnProcessing = true;
                base.OnCellEnter(e);
                if (this.myDisableColumns.Contains(this.Columns[e.ColumnIndex].Name)) SendKeys.Send("{Tab}");
                IsOnProcessing = false;
            }
            catch (Exception er)
            {
                IsOnProcessing = false;
                ErrorHandler(this, er);
            }
        }
        protected override void OnDefaultValuesNeeded(DataGridViewRowEventArgs e)
        {
            try
            {
                if (this.IsOnProcessing) return;
                this.IsOnProcessing = true;
                if (this.myOnValuesNeeded != null) myOnValuesNeeded(e);
                this.IsOnProcessing = false;
            }
            catch (Exception er)
            {
                this.IsOnProcessing = false;
                ErrorHandler(this, er); 
            }
        }

        public bool isLockEdit = false;

        //public void LockEdit(bool lockStat)
        //{
        //    //this.Enabled  = !lockStat;
        //    this.ReadOnly = lockStat;
        //    this.AllowUserToAddRows = !lockStat;
        //    this.AllowUserToDeleteRows = !lockStat;
        //}

        private myTypes.Permissions _myPermission = new myTypes.Permissions(255);
        public myTypes.Permissions myPermission
        {
            get
            {
                return _myPermission;
            }
        }
        public virtual void SetPermission(myTypes.Permissions value)
        {
            _myPermission = value;
        }

        public virtual void LockEdit(bool lockStat)
        {
            this.isLockEdit = lockStat || (this.myPermission.Edit == false && this.myPermission.Add == false);
            this.ReadOnly = this.isLockEdit;
            if (this.isLockEdit == false)
            {
                //Keep RO columms. Import/ Export function used RO to exclude fields to import/export
                for (int idx = 0; idx < this.myDisableColumns.Count; idx++)
                {
                    this.Columns[this.myDisableColumns[idx]].ReadOnly = true;
                }
            }
            this.AllowUserToAddRows = !lockStat && this.myPermission.Add;
            this.AllowUserToDeleteRows = !lockStat && this.myPermission.Delete;
        }
        public void ReOrderColumn(string[] colName)
        {
            for (int idx = 0; idx < colName.Length; idx++)
                this.Columns[colName[idx]].DisplayIndex = idx;
        }
        public void SetColumnVisible(string[] colName)
        {
            //Hide all column first
            for (int idx = 0; idx < this.ColumnCount; idx++) this.Columns[idx].Visible = false;
            for (int idx = 0; idx < colName.Length; idx++)
                SetColumnVisible(colName[idx], true);
        }
        public void SetColumnVisible(string colName, bool visibleMode)
        {
            this.Columns[colName].Visible = visibleMode;
        }
        public void SetColumnReadOnly(string colName, bool roMode)
        {
            colName = colName.ToUpper();
            for (int idx = 0; idx < this.ColumnCount; idx++)
            {
                if (this.Columns[idx].Name.ToUpper() == colName)
                {
                    this.Columns[idx].ReadOnly = roMode;
                    break;
                }
            }
        }
        public void DisbaleReadOnlyColumns()
        {
            this.myDisableColumns.Clear();
            for (int idx = 0; idx < this.ColumnCount; idx++)
            {
                if (!this.Columns[idx].ReadOnly) continue;
                this.myDisableColumns.Add(this.Columns[idx].Name);
            }
        }
        public bool IsValidCell(int RowIndex, int ColumnIndex)
        {
            return (RowIndex >= 0 && RowIndex < this.RowCount && ColumnIndex >= 0 && ColumnIndex < this.ColumnCount);
        }

        //Make Enter key works as Tabkey
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            //Make ENTER key work as TAB key for all controls except BUTTON
            if ((Settings.sysEnterSameAsTabKey && (msg.WParam.ToInt32() == (int)Keys.Enter)))
            {
                SendKeys.Send("{Tab}");
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        #region new event
        public delegate void OnCellEvent(object sender, GridEventArgs args);
        public event OnCellEvent myOnFind = null;
        public event OnCellEvent myOnCellValueChanged = null;
        public event OnCellEvent myOnCellValidated = null;
        public event OnCellEvent myOnNeedRefresh = null;

        private bool DoFind(int RowIndex, int ColumnIndex)
        {
            if (myOnFind == null) return false;
            GridEventArgs e = new GridEventArgs();
            e.RowIndex = RowIndex; e.ColumnIndex = ColumnIndex;
            myOnFind(this, e);
            if (myOnCellValueChanged != null) myOnCellValueChanged(this,new GridEventArgs(e.RowIndex, e.ColumnIndex));
            return true;
        }

        private void DoNeedRefresh()
        {
            if (myOnNeedRefresh != null)
            {
                myOnNeedRefresh(this, null);
            }
        }

        public myTypes.EventHandler myOnError = null;
        public void ErrorHandler(object sender, Exception er)
        {
            if (er == null || myOnError == null) return;
            myOnError(sender, er);
        }

        public delegate void OnDataExchangeNeed();
        public OnDataExchangeNeed myOnImport = null;
        public OnDataExchangeNeed myOnExport = null;

        //Remove all export/import handler
        public void RemoveAllOnExportHandler()
        {
            foreach (Delegate d in myOnExport.GetInvocationList()) myOnExport -= (OnDataExchangeNeed)d;
        }
        public void RemoveAllOnImportHandler()
        {
            if (this.myOnImport == null) return;
            foreach (Delegate d in this.myOnImport.GetInvocationList()) myOnImport -= (OnDataExchangeNeed)d;
        }

        public delegate void OnNewLineAdded(object sender);
        public delegate void OnNewLineAdd(object sender, DataGridViewRow currentRow, DataGridViewRowEventArgs addedRow);
        public event OnNewLineAdd myOnNewLineAdd = null;
        protected void DoAddNewLine(DataGridViewRow currentRow, DataGridViewRowEventArgs addedRow)
        {
            if (this.myOnNewLineAdd != null) myOnNewLineAdd(this, currentRow, addedRow);
        }

        #endregion event

        #region event handler
        private void copyLines_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.isLockEdit) return;
                if (this.SelectedRows.Count <= 0)
                {
                    SysLibs.ShowErrorMessage(language.GetString("selectDataToCopy"));
                    return;
                }
                this.CopyLines();
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }
        private void addLine_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.isLockEdit) return;
                this.AddLine();
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }
        private void deleteLine_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.isLockEdit) return;
                this.RemoveLine();
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }
        private void importToGrid_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.isLockEdit) return;
                if (this.myOnImport == null) return;
                this.myOnImport();
                this.Refresh();
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }
        private void exportGrid_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.myOnExport == null) return;
                this.myOnExport();
            }
            catch (Exception er)
            {
                ErrorHandler(this, er);
            }
        }
        #endregion

    }

    #region grid image cell
    // Adapted form "Defining Custom Column and Cell Types" in
    // "Presenting Data with the DataGridView Control in .NET 2.0" By Brian Noyes
    public class baseGridViewImageCell : DataGridViewImageCell
    {
        public baseGridViewImageCell()
        {
            this.ImageLayout = DataGridViewImageCellLayout.Zoom;
        }
        protected virtual System.Drawing.Image GetCellImage(string status) { return null; }
        protected override object GetFormattedValue(object value,
           int rowIndex, ref DataGridViewCellStyle cellStyle,
           System.ComponentModel.TypeConverter valueTypeConverter,
           System.ComponentModel.TypeConverter formattedValueTypeConverter,
           DataGridViewDataErrorContexts context)
        {
            string status = "";
            // Try to get the default value from the containing column
            baseGridViewImageColumn owningCol = OwningColumn as baseGridViewImageColumn;
            if (owningCol != null) status = owningCol.myValue;
            if (value is string) status = (string)value;
            cellStyle.Alignment = DataGridViewContentAlignment.TopCenter;
            return GetCellImage(status);
        }
    }
    public class baseGridViewImageColumn : DataGridViewColumn
    {
        public baseGridViewImageColumn(DataGridViewImageCell obj) : base(obj) { }
        public baseGridViewImageColumn() : base(new baseGridViewImageCell()) { }
        private string _myValue = "";
        public string myValue
        {
            get { return _myValue; }
            set { _myValue = value; }
        }

        public override object Clone()
        {
            baseGridViewImageColumn col = base.Clone() as baseGridViewImageColumn;
            col.myValue = _myValue;
            return col;
        }

        public override DataGridViewCell CellTemplate
        {
            get { return base.CellTemplate; }
            set
            {
                if (value == null)
                {
                    throw new ArgumentException("Invalid cell type, myColumns can only contain myDataGridViewImageCells");
                }
            }
        }
    }
    #endregion

    #region grid textBox

    public class DataGridViewTextBoxColumnExt : DataGridViewTextBoxColumn
    {
        public DataGridViewTextBoxColumnExt() : base()
        {
            CellTemplate = new DataGridViewTextBoxCellExt();
        }
        private bool _uppercase = false;
        public bool Uppercase
        {
            get { return _uppercase; }
            set { _uppercase = value; }
        }
    }

    public class DataGridViewTextBoxCellExt : DataGridViewTextBoxCell
    {
        public DataGridViewTextBoxCellExt()
            : base()
        {
        }
        public override Type EditType
        {
            get
            {
                if (((DataGridViewTextBoxColumnExt)this.OwningColumn).Uppercase)
                    return typeof(DataGridViewUpperCaseTextBoxEditingControl);
                return typeof(DataGridViewTextBoxEditingControl);
            }

        }
    }
    public class DataGridViewUpperCaseTextBoxEditingControl : DataGridViewTextBoxEditingControl
    {
        public DataGridViewUpperCaseTextBoxEditingControl() : base()
        {
            this.CharacterCasing = CharacterCasing.Upper;
        }
    }

    #endregion grid textBox

    public enum imageType : byte { Print, Detail, Scan, Edit, Cancel,Refresh,Select,Search,Next,Previous,Info,Return,Delete,View}
    public class gridViewImageCell : controls.baseGridViewImageCell
    {
        public gridViewImageCell()
        {
            this.ImageLayout = DataGridViewImageCellLayout.Normal;
        }
        protected override System.Drawing.Image GetCellImage(string status)
        {
            status = status.Trim();
            if (status == imageType.Scan.ToString()) return Properties.Resources.scanner;
            if (status == imageType.Detail.ToString()) return Properties.Resources.report;
            if (status == imageType.Print.ToString()) return Properties.Resources.print;
            if (status == imageType.Edit.ToString()) return Properties.Resources.edit;
            if (status == imageType.Cancel.ToString()) return Properties.Resources.remove;
            if (status == imageType.Refresh.ToString()) return Properties.Resources.refresh;

            if (status == imageType.Search.ToString()) return Properties.Resources.find;
            if (status == imageType.Info.ToString()) return Properties.Resources.about;
            
            if (status == imageType.Next.ToString()) return Properties.Resources.next;
            if (status == imageType.Previous.ToString()) return Properties.Resources.previous;

            if (status == imageType.Return.ToString()) return Properties.Resources.undo;
            if (status == imageType.Delete.ToString()) return Properties.Resources.small_delete;
            if (status == imageType.View.ToString()) return Properties.Resources.zoom;
            return null;
        }
    }
    public class gridViewImageColumn : controls.baseGridViewImageColumn
    {
        public gridViewImageColumn() : base(new gridViewImageCell()) { this.Width = 25; }
        public imageType myImageType
        {
            //get 
            //{
            //    this.ValueType
            //    baseGridViewImageColumn aa = (baseGridViewImageColumn)this.myValue;
            //    return (imageType)this.myValue; 
            //}
            set
            {
                this.myValue = value.ToString();
            }
        }
    }
}
